import typing
import shelve
from dataclasses import dataclass


@dataclass
class LogEntry:
    id: str
    op: str
    key: str
    val: str = ''
    term: int = 0


class LogEntries:

    def __init__(self, ident):
        self._dbm = shelve.open('node_%s_log' % ident)
        self.size = len(self._dbm)

    def append(self, entry: LogEntry):
        self._dbm[str(self.size)] = entry
        self.size += 1

    def latest(self) -> typing.Optional[LogEntry]:
        if self.size > 0:
            return self._dbm[str(self.size-1)]

    def pop(self) -> typing.Optional[LogEntry]:
        if self.size > 0:
            val = self._dbm.pop(str(self.size-1))
            self.size -= 1
            return val

    def _ensure_index(self, i: int):
        if i < 0:
            i = self.size + i
        if not 0 <= i < self.size:
            raise IndexError('index out of range')
        return i

    def __setitem__(self, i: int, entry: LogEntry):
        i = self._ensure_index(i)
        self._dbm[str(i)] = entry

    def __getitem__(self, i: int) -> LogEntry:
        i = self._ensure_index(i)
        return self._dbm[str(i)]

    def close(self):
        self._dbm.close()

    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.close()
